/*
 * Copyright (c) 2009 Frederic Daoud
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.stripesbook.rayures.stripes.extension;

import static net.sourceforge.stripes.controller.LifecycleStage.EventHandling;
import static net.sourceforge.stripes.controller.LifecycleStage.HandlerResolution;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.config.ConfigurableComponent;
import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.controller.ExecutionContext;
import net.sourceforge.stripes.controller.Interceptor;
import net.sourceforge.stripes.controller.Intercepts;
import net.sourceforge.stripes.controller.LifecycleStage;
import org.stripesbook.rayures.action.RayuresActionBean;
import org.stripesbook.rayures.service.ViewPreparer;
import org.stripesbook.rayures.service.impl.ViewPreparerImpl;
import org.stripesbook.rayures.util.Resolver;

/**
 * Interceptor that provides support for <i>void event handlers</i> and <i>Rayures tags</i>.
 *
 * <p>
 * For event handlers that return {@code void}, the interceptor checks for a {@code null}
 * {@link Resolution}. If that is the case, and the current action bean implements
 * {@link RayuresActionBean}, the interceptor first checks for {@link RayuresActionBean#getResolution()},
 * and if that returns {@code null}, it uses a {@link ForwardResolution} to
 * {@link RayuresActionBean#getDefaultPath()}.
 * </p>
 *
 * <p>
 * The interceptor also checks if the action bean implements {@link RayuresActionBean}. If so, its
 * {@link RayuresActionBean#getView()} method is invoked and the returned object is set as a
 * request attribute under the key {@value org.stripesbook.rayures.util.Constants#ATTR_VIEW}.
 * </p>
 *
 * <p>
 * For Rayures tags, the interceptor delegates the work to an implementation of
 * {@link ViewPreparer}, which is {@link ViewPreparerImpl} by default. This can be changed by
 * placing the implementing class in an extension package or by declaring it in {@code web.xml}
 * as an {@code init-param} of {@code StripesFilter}, under the key
 * {@value org.stripesbook.rayures.util.Constants#CONFIG_VIEW_PREPARER}.
 * </p>
 *
 * @author Frederic Daoud
 */
@Intercepts({HandlerResolution, EventHandling})
public class RayuresViewInterceptor implements Interceptor, ConfigurableComponent {

  private ViewPreparer viewPreparer;

  public void init(Configuration config) throws Exception {
    viewPreparer = Resolver.resolve(config, ViewPreparer.class);
  }

  /**
   * Executes after {@link LifecycleStage#HandlerResolution} and {@link LifecycleStage#EventHandling}.
   *
   * <p>
   * After {@link LifecycleStage#HandlerResolution}, delegates to the {@link ViewPreparer} to do the work
   * necessary for preparing Rayures tag support.
   * </p>
   * 
   * <p>
   * After {@link LifecycleStage#EventHandling}, checks for a {@code null} {@link Resolution} and uses
   * {@link RayuresActionBean} to determine the resolution. Also looks for a view object and, if found,
   * sets it as a request attribute.
   * </p>
   */
  public Resolution intercept(ExecutionContext execContext) throws Exception {
    Resolution resolution = execContext.proceed();
    LifecycleStage stage = execContext.getLifecycleStage();

    ActionBean actionBean = execContext.getActionBean();

    if (stage == HandlerResolution) {
      viewPreparer.prepareView(actionBean, execContext.getActionBeanContext().getEventName());
    }
    else if (stage == EventHandling && resolution == null) {
      resolution = handleNullResolution(actionBean);
    }
    return resolution;
  }

  protected Resolution handleNullResolution(ActionBean actionBean) {
    Resolution resolution = null;

    if (actionBean instanceof RayuresActionBean) {
      RayuresActionBean rayuresActionBean = (RayuresActionBean) actionBean;
      Resolution setResolution = rayuresActionBean.getResolution();

      if (setResolution != null) {
        resolution = setResolution;
        rayuresActionBean.setResolution(null);
      }
      else {
        String defaultPath = rayuresActionBean.getDefaultPath();
        resolution = new ForwardResolution(defaultPath);
      }
    }
    return resolution;
  }
}
